package org.jeecg.modules.friends.friendsinfo.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.MakeFriendsBaseException;
import org.jeecg.modules.friends.dao.VipUserDAO;
import org.jeecg.modules.friends.enums.FriendsStatusEnum;
import org.jeecg.modules.friends.enums.OperateTypeEnum;
import org.jeecg.modules.friends.friendsinfo.dto.ApplyResultDTO;
import org.jeecg.modules.friends.friendsinfo.dto.FriendsCountInfo;
import org.jeecg.modules.friends.friendsinfo.dto.FriendsInfoDTO;
import org.jeecg.modules.friends.friendsinfo.entity.FriendsInfo;
import org.jeecg.modules.friends.friendsinfo.mapper.FriendsInfoMapper;
import org.jeecg.modules.friends.friendsinfo.param.FriendsListParam;
import org.jeecg.modules.friends.friendsinfo.param.MakeFriendsParam;
import org.jeecg.modules.friends.friendsinfo.param.OperateApplyParam;
import org.jeecg.modules.friends.friendsinfo.service.IFriendsInfoService;
import org.jeecg.modules.friends.model.VipUserDO;
import org.jeecg.modules.friends.service.TicketRecordService;
import org.jeecg.modules.friends.service.impl.LCD;
import org.jeecg.modules.friends.user.entity.User;
import org.jeecg.modules.friends.user.mapper.UserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;


/**
 * @Description: 好友信息表
 * @Author: jeecg-boot
 * @Date: 2024-05-15
 * @Version: V1.0
 */
@Service
public class FriendsInfoServiceImpl extends ServiceImpl<FriendsInfoMapper, FriendsInfo> implements IFriendsInfoService {

    @Autowired
    private FriendsInfoMapper friendsInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TicketRecordService ticketRecordService;

    @Autowired
    private VipUserDAO vipUserDAO;

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    private static final SimpleDateFormat sdfDetail = new SimpleDateFormat("yyyy");

    @Override
    public FriendsCountInfo queryFriendsCountInfo(Long userId) {
        FriendsCountInfo friendsCountInfo = new FriendsCountInfo();
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, userId);
        lambdaQueryWrapper.eq(FriendsInfo::getStatus, FriendsStatusEnum.FRIEND.getCode());
        Long friendsCount = friendsInfoMapper.selectCount(lambdaQueryWrapper);
        friendsCountInfo.setFriendsCount(friendsCount);
        lambdaQueryWrapper.clear();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, userId);
        List<Integer> notInStatus =
                Lists.newArrayList(FriendsStatusEnum.FRIEND.getCode(), FriendsStatusEnum.PASSED.getCode());
        lambdaQueryWrapper.notIn(FriendsInfo::getStatus, notInStatus);
        Long fromCount = friendsInfoMapper.selectCount(lambdaQueryWrapper);
        friendsCountInfo.setFollowsCount(fromCount);
        lambdaQueryWrapper.clear();
        lambdaQueryWrapper.eq(FriendsInfo::getToUserId, userId);
        lambdaQueryWrapper.notIn(FriendsInfo::getStatus, notInStatus);
        Long fansCount = friendsInfoMapper.selectCount(lambdaQueryWrapper);
        friendsCountInfo.setFansCount(fansCount);
        lambdaQueryWrapper.eq(FriendsInfo::getUnread, true);
        Long unreadCount = friendsInfoMapper.selectCount(lambdaQueryWrapper);
        friendsCountInfo.setFansUnreadCount(unreadCount);
        return friendsCountInfo;
    }

    @Override
    public ApplyResultDTO addFriends(MakeFriendsParam makeFriendsParam, Long fromUserId) {
        //校验券
        ApplyResultDTO applyResultDTO = new ApplyResultDTO();
        VipUserDO vipUserDO = vipUserDAO.findByUserId(fromUserId);
        if (Objects.isNull(vipUserDO) || (vipUserDO.getVipEndDate() <= System.currentTimeMillis()
                && vipUserDO.getTicketLeft() <= 0)) {
            throw new MakeFriendsBaseException(CommonConstant.NOT_VIP_TICKET_NOT_ENOUGH, "好有券可用额度不足");
        } else if (vipUserDO.getTicketLeft() <= 0) {
            throw new MakeFriendsBaseException(CommonConstant.VIP_TICKET_NOT_ENOUGH, "好有券可用额度不足");
        }
        List<FriendsInfo> fromUserDbInfo = queryByFromUserIdAndToUserId(fromUserId, makeFriendsParam.getToUserId());
        fromUserDbInfo = ListUtils.emptyIfNull(fromUserDbInfo).stream()
                .filter((element) -> !element.getStatus().equals(FriendsStatusEnum.PASSED.getCode()))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(fromUserDbInfo)) {
            throw new MakeFriendsBaseException(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, "您已申请过,不能发起申请");
        }
        List<FriendsInfo> toUserDbInfo = queryByFromUserIdAndToUserId(makeFriendsParam.getToUserId(), fromUserId);
        FriendsInfo isApplyed = new FriendsInfo();
        if (CollectionUtils.isNotEmpty(toUserDbInfo)) {
            Set<Integer> statusSet = toUserDbInfo.stream().map(FriendsInfo::getStatus).collect(Collectors.toSet());
            if (statusSet.contains(FriendsStatusEnum.FRIEND.getCode())) {
                throw new MakeFriendsBaseException("已是好友");
            }
            isApplyed =
                    toUserDbInfo.stream().filter(x -> x.getStatus() == FriendsStatusEnum.APPLY.getCode()).findFirst()
                            .orElse(new FriendsInfo());
        }
        if (Objects.nonNull(isApplyed) && isApplyed.getId() != null) {
            //对方已经申请 就直接通过好友
            List<Long> userIds = new ArrayList<>();
            userIds.add(fromUserId);
            userIds.add(makeFriendsParam.getToUserId());
            List<User> userList = userMapper.selectBatchIds(userIds);
            if (CollectionUtils.isNotEmpty(userList)) {
                userList.stream().forEach(x -> {
                    if (x.getId() == fromUserId) {
                        applyResultDTO.setSelfUserHeadPic(x.getHeadPicUrl());
                    } else {
                        applyResultDTO.setToUserHeadPic(x.getHeadPicUrl());
                    }
                });
            }
            isApplyed.setStatus(FriendsStatusEnum.AGREE.getCode());

            friendsInfoMapper.updateById(isApplyed);

            //新增一条好友信息
            FriendsInfo newFriends = new FriendsInfo();
            BeanUtils.copyProperties(isApplyed, newFriends);
            newFriends.setId(null);
            newFriends.setStatus(FriendsStatusEnum.FRIEND.getCode());
            friendsInfoMapper.insert(newFriends);

            //新增一条好友信息
            FriendsInfo newFriends2 = new FriendsInfo();
            BeanUtils.copyProperties(isApplyed, newFriends2);
            newFriends2.setId(null);
            newFriends2.setStatus(FriendsStatusEnum.FRIEND.getCode());
            newFriends2.setFromUserId(isApplyed.getToUserId());
            newFriends2.setToUserId(isApplyed.getFromUserId());
            friendsInfoMapper.insert(newFriends2);
            return applyResultDTO;
        }
        //生成一条好友请求
        FriendsInfo friendsInfo = new FriendsInfo();
        friendsInfo.setAddTime(new Date());
        friendsInfo.setStatus(FriendsStatusEnum.APPLY.getCode());
        friendsInfo.setUpdateTime(new Date());
        friendsInfo.setFromUserId(fromUserId);
        friendsInfo.setToUserId(makeFriendsParam.getToUserId());
        friendsInfo.setRemark(makeFriendsParam.getRemark());
        friendsInfo.setUnread(true);
        friendsInfoMapper.insert(friendsInfo);
        ticketRecordService.addTicketRecord(fromUserId, friendsInfo.getId());
        return applyResultDTO;
    }

    @Override
    @Transactional
    public Boolean operateApply(OperateApplyParam operateApplyParam, Long userId) {
        FriendsInfo friendsInfo = friendsInfoMapper.selectById(operateApplyParam.getId());

        if (OperateTypeEnum.PASS.getCode() == operateApplyParam.getOperateType()) {

            friendsInfo.setStatus(FriendsStatusEnum.AGREE.getCode());

            friendsInfoMapper.updateById(friendsInfo);

            //新增一条好友信息
            FriendsInfo newFriends = new FriendsInfo();
            BeanUtils.copyProperties(friendsInfo, newFriends);
            newFriends.setId(null);
            newFriends.setStatus(FriendsStatusEnum.FRIEND.getCode());
            friendsInfoMapper.insert(newFriends);

            //新增一条好友信息
            FriendsInfo newFriends2 = new FriendsInfo();
            BeanUtils.copyProperties(friendsInfo, newFriends2);
            newFriends2.setId(null);
            newFriends2.setStatus(FriendsStatusEnum.FRIEND.getCode());
            newFriends2.setFromUserId(friendsInfo.getToUserId());
            newFriends2.setToUserId(friendsInfo.getFromUserId());
            friendsInfoMapper.insert(newFriends2);
            return true;
        }

        if (OperateTypeEnum.REJECT.getCode() == operateApplyParam.getOperateType()) {
            friendsInfo.setStatus(FriendsStatusEnum.REJECT.getCode());
            friendsInfoMapper.updateById(friendsInfo);
            ticketRecordService.cancelTicketRecord(friendsInfo.getId());
            return true;
        }
        return false;
    }

    @Override
    public Page<FriendsInfoDTO> friendsList(FriendsListParam param, Long id) {
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (param.getType() == 3) {
            lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, id);
            lambdaQueryWrapper.eq(FriendsInfo::getStatus, FriendsStatusEnum.FRIEND.getCode());
            lambdaQueryWrapper.orderByDesc(FriendsInfo::getUpdateTime);
        }
        List<Integer> notInStatus =
                Lists.newArrayList(FriendsStatusEnum.FRIEND.getCode(), FriendsStatusEnum.PASSED.getCode());
        if (param.getType() == 2) {
            lambdaQueryWrapper.eq(FriendsInfo::getToUserId, id);
            lambdaQueryWrapper.notIn(FriendsInfo::getStatus, notInStatus);
            lambdaQueryWrapper.orderByDesc(FriendsInfo::getAddTime);
            FriendsInfo friendsInfo = new FriendsInfo();
            friendsInfo.setUnread(false);
            friendsInfoMapper.update(friendsInfo, lambdaQueryWrapper);
        }
        if (param.getType() == 1) {
            lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, id);
            lambdaQueryWrapper.notIn(FriendsInfo::getStatus, notInStatus);
            lambdaQueryWrapper.orderByDesc(FriendsInfo::getUpdateTime);
        }
        Page<FriendsInfo> friendsInfoIPage = new Page<>(param.getPageNo(), param.getPageSize());
        friendsInfoIPage = friendsInfoMapper.selectPage(friendsInfoIPage, lambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(friendsInfoIPage.getRecords())) {
            Page<FriendsInfoDTO> friendsInfoDTOPage = convertToDTO(friendsInfoIPage, param.getType());
            return friendsInfoDTOPage;
        }
        return new Page<>();
    }

    @Override
    public List<FriendsInfo> queryPassedList(Long id) {
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, id);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(FriendsStatusEnum.FRIEND.getCode());
        statusList.add(FriendsStatusEnum.PASSED.getCode());
        statusList.add(FriendsStatusEnum.APPLY.getCode());
        lambdaQueryWrapper.in(FriendsInfo::getStatus, statusList);
        return friendsInfoMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public void passUser(MakeFriendsParam makeFriendsParam, Long fromUserId) {
        //生成一条PASS记录
        FriendsInfo friendsInfo = new FriendsInfo();
        friendsInfo.setAddTime(new Date());
        friendsInfo.setStatus(FriendsStatusEnum.PASSED.getCode());
        friendsInfo.setUpdateTime(new Date());
        friendsInfo.setFromUserId(fromUserId);
        friendsInfo.setToUserId(makeFriendsParam.getToUserId());
        friendsInfo.setRemark(makeFriendsParam.getRemark());
        friendsInfo.setUnread(true);
        friendsInfoMapper.insert(friendsInfo);
    }

    @Override
    public List<FriendsInfo> queryByFromUserIdAndToUserId(Long fromUserId, Long toUserId) {
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, fromUserId);
        lambdaQueryWrapper.eq(FriendsInfo::getToUserId, toUserId);
        List<FriendsInfo> friendsInfos = friendsInfoMapper.selectList(lambdaQueryWrapper);

        return friendsInfos;
    }

    @Override
    public void deleteByUserId(Long userId) {
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, userId);
        friendsInfoMapper.delete(lambdaQueryWrapper);
        lambdaQueryWrapper.clear();
        lambdaQueryWrapper.eq(FriendsInfo::getToUserId, userId);
        friendsInfoMapper.delete(lambdaQueryWrapper);
    }

    @Override
    public void resetFriendRecord(List<Long> userIdList) {
        if (CollectionUtil.isEmpty(userIdList)) {
            return;
        }
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(FriendsInfo::getFromUserId, userIdList);
        lambdaQueryWrapper.eq(FriendsInfo::getStatus, FriendsStatusEnum.PASSED.getCode());
        friendsInfoMapper.delete(lambdaQueryWrapper);
    }

    @Override
    public long queryFriendsCountToday(Long userId) {
        LambdaQueryWrapper<FriendsInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(FriendsInfo::getFromUserId, userId);
        // 今天
        lambdaQueryWrapper.ge(FriendsInfo::getAddTime, DateUtil.beginOfDay(new Date()));
        lambdaQueryWrapper.lt(FriendsInfo::getAddTime, DateUtil.endOfDay(new Date()));

        return friendsInfoMapper.selectCount(lambdaQueryWrapper);
    }

    private Page<FriendsInfoDTO> convertToDTO(Page<FriendsInfo> friendsInfoIPage, Integer type) {
        Page<FriendsInfoDTO> friendsInfoDTOPage = new Page<>(friendsInfoIPage.getCurrent(), friendsInfoIPage.getSize());
        friendsInfoDTOPage.setTotal(friendsInfoIPage.getTotal());
        friendsInfoDTOPage.setPages(friendsInfoIPage.getPages());
        if (CollectionUtils.isEmpty(friendsInfoIPage.getRecords())) {
            return friendsInfoDTOPage;
        }
        List<User> userList = Lists.newArrayList();
        List<Long> userIds;
        if (type == 3 || type == 1) {
            userIds = friendsInfoIPage.getRecords().stream().map(FriendsInfo::getToUserId).collect(Collectors.toList());
        } else {
            userIds =
                    friendsInfoIPage.getRecords().stream().map(FriendsInfo::getFromUserId).collect(Collectors.toList());
        }
        userList = userMapper.selectBatchIds(userIds);
        if (CollectionUtils.isNotEmpty(userList)) {
            Map<Long, User> userMap =
                    userList.stream().collect(Collectors.toMap(User::getId, Function.identity(), (a, b) -> a));
            List<FriendsInfoDTO> friendsInfoDTOS = friendsInfoIPage.getRecords().stream().map(friendsInfo -> {
                FriendsInfoDTO friendsInfoDTO = new FriendsInfoDTO();
                friendsInfoDTO.setId(friendsInfo.getId());
                friendsInfoDTO.setApplyStatus(friendsInfo.getStatus());

                if (type == 3 || type == 1) {
                    friendsInfoDTO.setUserId(friendsInfo.getToUserId());
                } else {
                    friendsInfoDTO.setUserId(friendsInfo.getFromUserId());
                }
                friendsInfoDTO.setCreateDate(sdf.format(friendsInfo.getAddTime()));
                User user = userMap.get(friendsInfoDTO.getUserId());
                if (Objects.nonNull(user)) {
                    if (type == 3) {
                        friendsInfoDTO.setWechat(user.getWechat());
                    }
                    friendsInfoDTO.setUserNickname(user.getNickname());
                    friendsInfoDTO.setUserHeadPic(user.getHeadPicUrl());
                    //friendsInfoDTO.setUserDesc(user.getUserDesc());
                    friendsInfoDTO.setUserStatus(user.getStatus());
                    String year = "x";
                    if (StringUtils.isNotBlank(user.getBirthday())) {
                        year = user.getBirthday().substring(0, 4);
                        year = year.substring(2);
                    }
                    friendsInfoDTO.setUserDesc(year + "年" + " 现居" + user.getCurrentResidence());

                }
                return friendsInfoDTO;
            }).collect(Collectors.toList());
            friendsInfoDTOPage.setRecords(friendsInfoDTOS);
        }


        return friendsInfoDTOPage;

    }
}
